package modelUtils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.lang.model.element.VariableElement;

import org.apache.commons.lang3.StringUtils;

import freemarker.template.Template;

/**
 * 代码生成器工具类
 * @ClassName:  CodeGenerateUtils   
 * @Description:TODO   
 * @author: zhangxz 
 * @date:   2018年8月17日 下午10:59:59   
 *     
 * @Copyright: 2018 www.zxz1990.xin Inc. All rights reserved. 
 * 注意：9091优惠券
 */
public class CodeGenerateUtils {

	public static final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	/**当前时间*/
	public static final String CURRENT_DATE = sf.format(new Date());
	// 以下根据项目结合自己实际情况修改对应的值----------------------------------
	/**数据库驱动*/
	public static final String DRIVER = "com.mysql.jdbc.Driver";
	/**数据库链接*/
	public static final String URL = "jdbc:mysql://127.0.0.1:3306/lawbzoffice20181218?autoReconnect=true&useUnicode=true&characterEncoding=utf8";
	/**数据库用户*/
	public static final String USER = "root";
	/**数据库密码*/
	public static final String PASSWORD = "1234";
	/**生成文件的存放文件夹*/
	public static final String DISK_PATH = "D:/src";
	/**生成类注释中的作者*/
	public static final String AUTHOR = "zhangxz";
	/**基础类所在的包*/
	public static final String COMMEN_PAGE="com.lingnet.common";
	/**包名 */
	public static final String PACKAGE_NAME = "com.lingnet.lawe";
	/**业务模块包名字*/
	public static final String MODULE_PACKAGE_NAME = "generalprogram";
	/**数据库表名*/
	public static final String TABLE_NAME="lawe_form";
	/**实体的类前缀（类似该项目的前缀，例如:SysEntity 其中Sys则为公共的前缀）*/
	public static final String ENTITY_PREFIX = "";
	/**表注释*/
	public static final String TABLE_COMMENT = "案件文书列表";
	public static final String IGNORE_COLUMN = "id,createdate,modifydate";
	
	
	public static void main(String[] args) {
		Map<String,String> data = new HashMap<>();
		data.put("driver", DRIVER);
    	data.put("url", URL);
    	data.put("user", USER);
    	data.put("password", PASSWORD);
    	data.put("disk_path", DISK_PATH);
    	data.put("author", AUTHOR);
    	data.put("commen_page", COMMEN_PAGE);
    	data.put("package_name", PACKAGE_NAME);
    	data.put("module_package_name", MODULE_PACKAGE_NAME);
    	data.put("table_name", TABLE_NAME);
    	data.put("entity_prefix", ENTITY_PREFIX);
    	data.put("table_comment", TABLE_COMMENT);
    	data.put("ignore_column", IGNORE_COLUMN);
		generateCode(data);
	}
	
	public static boolean generateCode(Map<String,String> params) {
		String driver = params.get("driver");
		String url = params.get("url");
		String user = params.get("user");
		String password = params.get("password");
		String disk_path = params.get("disk_path");
		String author = params.get("author");
		String commen_page = params.get("commen_page");
		String package_name = params.get("package_name");
		String module_package_name = params.get("module_package_name");
		String table_name = params.get("table_name");
		String entity_prefix = params.get("entity_prefix");
		String table_comment = params.get("table_comment");
		String ignore_column = params.get("ignore_column");
		TableInforClass tableInfo;
		try {
			Map<String,Object> dataMap = new HashMap<>();
			dataMap.put("author",author);
	        dataMap.put("date",CURRENT_DATE);
	        dataMap.put("package_name",package_name);
	        dataMap.put("module_package_name",module_package_name);
	        dataMap.put("common_package",commen_page);
			// 获取数据库表的表信息 表名、注释、字段信息等
			tableInfo = getTableInfo(getConnection(driver,url,user,password),table_name,table_comment,ignore_column);
			// 生成实体类
			generateEntityFile(disk_path,tableInfo,dataMap);
			// 生成service接口
			generateServiceFile(disk_path,tableInfo,dataMap);
			// 生成service接口实现类
			generateServiceImplFile(disk_path,tableInfo,dataMap);
			// 生成dao接口
			generateDaoFile(disk_path,tableInfo,dataMap);
			// 生成dao接口实现类
			generateDaoImplFile(disk_path,tableInfo,dataMap);
			// 生成Controller/Action
			generateControllerFile(disk_path,entity_prefix,tableInfo,dataMap);
			// 生成Action
			generateActionFile(disk_path,entity_prefix,tableInfo,dataMap);
			return true;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		
	}
	
	
	/**
	 * 获取数据链接
	 * @Title: getConnection   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @return
	 * @param: @throws Exception      
	 * @return: Connection      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月17日 下午11:23:29   
	 * @version V1.0
	 */
	public static Connection getConnection(String driver,String url,String username,String password) throws Exception{
		// 数据库驱动
		Class.forName(driver);
		Connection connection = DriverManager.getConnection(url, username, password);
		return connection;
	}
	
	/**
	 * 获取数据库表的表信息 表名、注释、字段信息等
	 * @Title: getTableInfo   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param connection
	 * @param: @return
	 * @param: @throws Exception      
	 * @return: TableInfoClass      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月18日 下午6:37:09   
	 * @version V1.0
	 */
	public static TableInforClass getTableInfo(Connection connection,String tableNames,String tableComment,String ignoreColumn) throws Exception{
		TableInforClass tableInfo = new TableInforClass();
		List<ColumnInforClass> columnInfoList = new ArrayList<>();
		DatabaseMetaData metaData = connection.getMetaData();
		ResultSet resultSet = metaData.getTables(null, "%", tableNames, new String[] { "TABLE" });
		while (resultSet.next()) {
			 String tableName=resultSet.getString("TABLE_NAME").toLowerCase();
			 String changeTableName = replaceUnderLineAndUpperCase(tableName);
             //String remarkes = resultSet.getString("REMARKS");
             tableInfo.setTableName(tableName);
             tableInfo.setChangeTableName(changeTableName);
             tableInfo.setTableComment(tableComment);
		}
		columnInfoList = getColumnInfors(connection,tableNames,ignoreColumn);
		tableInfo.setColumnsInfo(columnInfoList);
		return tableInfo;
	}
	
	/**
	 * 获取数据库表所有字段的信息
	 * @Title: getResultSet   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param connection
	 * @param: @return      
	 * @return: List<ColumnInfoClass>      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月17日 下午11:29:10   
	 * @version V1.0
	 * @throws Exception 
	 */
	public static List<ColumnInforClass> getColumnInfors(Connection connection,String tableName, String ignorColumns) throws Exception{
		// 忽略字段数组
		String[] ignorColumnArr = {};
		if(ignorColumns != null && !"".equals(ignorColumns)) {
			ignorColumnArr = ignorColumns.split(",");
		}
		
		List<ColumnInforClass> columnInfoList = new ArrayList<>();
		DatabaseMetaData metaData = connection.getMetaData();
		ResultSet columns = metaData.getColumns(null, "%", tableName, "%");
		loop1: while(columns.next()){
			ColumnInforClass columnInfoClass = new ColumnInforClass();
			// 忽略字段
			if(ignorColumnArr != null && ignorColumnArr.length > 0) {
				for(String ignorColumn : ignorColumnArr) {
					if(ignorColumn.equals(columns.getString("COLUMN_NAME").toLowerCase())){
						
						continue loop1;
					}
				}
			}
			// 获取字段名称
			columnInfoClass.setColumnName(columns.getString("COLUMN_NAME"));
			// 获取字段类型
			columnInfoClass.setColumnType(columns.getString("TYPE_NAME"));
			// 获取字段长度
			columnInfoClass.setColumnSize(String.valueOf(columns.getInt("COLUMN_SIZE")));
			// 转换字段名称，如 sys_name 变成 SysName
			columnInfoClass.setChangeColumnName(replaceUnderLineAndUpperCase(columns.getString("COLUMN_NAME")));
			// 字段在数据库中的注释
			columnInfoClass.setColumnComment(columns.getString("REMARKS"));
			columnInfoList.add(columnInfoClass);
		}
		return columnInfoList;
	}
	/**
	 * 生成实体类
	 * @Title: generateEntitylFile   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param tableInfo
	 * @param: @throws Exception      
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月19日 下午3:42:27   
	 * @version V1.0
	 */
	public static void generateEntityFile(String diskPath,TableInforClass tableInfo,Map<String,Object> dataMap) throws Exception{
		// 文件后缀
		final String suffix = ".java";
		// 生成文件的文件夹
		String dirpath = diskPath + "/entity/";
		String path = diskPath + "/entity/" +tableInfo.getChangeTableName() + suffix;
		final String templateName = "Entity.ftl";
		// 创建文件夹
		File dirFile = new File(dirpath);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		// 生成的映射文件
		File mapperFile = new File(path);
		//Map<String,Object> dataMap = new HashMap<>();
		
		// 获取数据库表的字段信息
		List<ColumnInforClass> columnInfoList = tableInfo.getColumnsInfo();
		// 表信息
		dataMap.put("tableInfo", tableInfo);
		// 数据库字段信息集合
		dataMap.put("entity_columns", columnInfoList);
		dataMap.put("nowDateLong", String.valueOf(new Date().getTime()));
		generateFileByTemplate(templateName, mapperFile, dataMap);
		
	}
	/**
	 * 生成service接口
	 * @Title: generateServicelFile   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param tableInfo
	 * @param: @throws Exception      
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月19日 下午4:19:22   
	 * @version V1.0
	 */
	public static void generateServiceFile(String diskPath,TableInforClass tableInfo,Map<String,Object> dataMap) throws Exception{
		// 文件后缀
		final String suffix = ".java";
		// 生成文件的文件夹
		String dirpath = diskPath + "/service/";
		String path = diskPath + "/service/" +tableInfo.getChangeTableName()+"Service" + suffix;
		final String templateName = "Service.ftl";
		// 创建文件夹
		File dirFile = new File(dirpath);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		// 生成的映射文件
		File mapperFile = new File(path);
		//Map<String,Object> dataMap = new HashMap<>();
		
		dataMap.put("tableInfo", tableInfo);
		generateFileByTemplate(templateName, mapperFile, dataMap);
	}
	/**
	 * 生成service接口实现类
	 * @Title: generateServiceImplFile   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param tableInfo
	 * @param: @throws Exception      
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月19日 下午4:51:51   
	 * @version V1.0
	 */
	public static void generateServiceImplFile(String diskPath,TableInforClass tableInfo,Map<String,Object> dataMap) throws Exception{
		// 文件后缀
		final String suffix = ".java";
		// 生成文件的文件夹
		String dirpath = diskPath + "/service/impl/";
		String path = diskPath + "/service/impl/" +tableInfo.getChangeTableName()+"ServiceImpl" + suffix;
		final String templateName = "ServiceImpl.ftl";
		// 创建文件夹
		File dirFile = new File(dirpath);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		// 生成的映射文件
		File mapperFile = new File(path);
		//Map<String,Object> dataMap = new HashMap<>();
		
		dataMap.put("tableInfo", tableInfo);
		generateFileByTemplate(templateName, mapperFile, dataMap);
	}
	/**
	 * 生成dao接口
	 * @Title: generateServiceImplFile   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param tableInfo
	 * @param: @throws Exception      
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月19日 下午4:51:51   
	 * @version V1.0
	 */
	public static void generateDaoFile(String diskPath,TableInforClass tableInfo,Map<String,Object> dataMap) throws Exception{
		// 文件后缀
		final String suffix = ".java";
		// 生成文件的文件夹
		String dirpath = diskPath + "/dao/";
		String path = diskPath + "/dao/" +tableInfo.getChangeTableName()+"Dao" + suffix;
		final String templateName = "Dao.ftl";
		// 创建文件夹
		File dirFile = new File(dirpath);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		// 生成的映射文件
		File mapperFile = new File(path);
		//Map<String,Object> dataMap = new HashMap<>();
		
		dataMap.put("tableInfo", tableInfo);
		generateFileByTemplate(templateName, mapperFile, dataMap);
	}
	/**
	 * 生成dao接口实现类
	 * @Title: generateServiceImplFile   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param tableInfo
	 * @param: @throws Exception      
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月19日 下午4:51:51   
	 * @version V1.0
	 */
	public static void  generateDaoImplFile(String diskPath, TableInforClass tableInfo,Map<String,Object> dataMap) throws Exception{
		// 文件后缀
		final String suffix = ".java";
		// 生成文件的文件夹
		String dirpath = diskPath + "/dao/impl/";
		String path = diskPath + "/dao/impl/" +tableInfo.getChangeTableName()+"DaoImpl" + suffix;
		final String templateName = "DaoImpl.ftl";
		// 创建文件夹
		File dirFile = new File(dirpath);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		// 生成的映射文件
		File mapperFile = new File(path);
		//Map<String,Object> dataMap = new HashMap<>();
		
		dataMap.put("tableInfo", tableInfo);
		generateFileByTemplate(templateName, mapperFile, dataMap);
	}
	/**
	 * 生成controller
	 * @Title: generateControllerFile   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param tableInfo
	 * @param: @throws Exception      
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月20日 上午12:07:59   
	 * @version V1.0
	 */
	public static void  generateControllerFile(String diskPath,String entityPrefix
			,TableInforClass tableInfo,Map<String,Object> dataMap) throws Exception{
		// 文件后缀
		final String suffix = ".java";
		String changTableNameTemp = tableInfo.getChangeTableName();
		// 判断实体类名包含不包含指定的前缀，若包含则将前缀去掉
		if(changTableNameTemp.contains(replaceUnderLineAndUpperCase(entityPrefix))){
			changTableNameTemp = changTableNameTemp.replace(replaceUnderLineAndUpperCase(entityPrefix), "");
		}
		// 生成文件的文件夹
		String dirpath = diskPath + "/controller/";
		String path = diskPath + "/controller/" +changTableNameTemp+"Controller" + suffix;
		final String templateName = "Controller.ftl";
		// 创建文件夹
		File dirFile = new File(dirpath);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		// 生成的映射文件
		File mapperFile = new File(path);
		//Map<String,Object> dataMap = new HashMap<>();
		
		dataMap.put("nowDateLong", String.valueOf(new Date().getTime()));
		// 取去除前缀以后的名称作为Controller名称
		dataMap.put("changTableNameTemp", changTableNameTemp);
		dataMap.put("tableInfo", tableInfo);
		generateFileByTemplate(templateName, mapperFile, dataMap);
	}
	
	/**
	 * 生成action
	 * @Title: generateActionFile   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param tableInfo
	 * @param: @throws Exception      
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月20日 上午12:07:59   
	 * @version V1.0
	 */
	public static void  generateActionFile(String diskPath,String entityPrefix
			,TableInforClass tableInfo,Map<String,Object> dataMap) throws Exception{
		// 文件后缀
		final String suffix = ".java";
		String changTableNameTemp = tableInfo.getChangeTableName();
		// 判断实体类名包含不包含指定的前缀，若包含则将前缀去掉
		if(changTableNameTemp.contains(replaceUnderLineAndUpperCase(entityPrefix))){
			changTableNameTemp = changTableNameTemp.replace(replaceUnderLineAndUpperCase(entityPrefix), "");
		}
		// 生成文件的文件夹
		String dirpath = diskPath + "/action/";
		String path = diskPath + "/action/" +changTableNameTemp+"Action" + suffix;
		final String templateName = "Action.ftl";
		// 创建文件夹
		File dirFile = new File(dirpath);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		// 生成的映射文件
		File mapperFile = new File(path);
		//Map<String,Object> dataMap = new HashMap<>();
		
		dataMap.put("nowDateLong", String.valueOf(new Date().getTime()));
		// 取去除前缀以后的名称作为Controller名称
		dataMap.put("changTableNameTemp", changTableNameTemp);
		dataMap.put("tableInfo", tableInfo);
		generateFileByTemplate(templateName, mapperFile, dataMap);
	}
	
	/**
	 * 根据相关参数使用模板生成相关代码
	 * @Title: generateFileByTemplate   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param templateName 模板名称
	 * @param: @param file 生成的文件
	 * @param: @param dataMap 模板中需要的参数 键值对 
	 * @return: void      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月19日 下午12:33:52   
	 * @version V1.0
	 * @throws Exception 
	 */
	public static void generateFileByTemplate(final String templateName,File file,Map<String,Object> dataMap) throws Exception{
		Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
		FileOutputStream fos = new FileOutputStream(file);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"));
        template.process(dataMap, out);
        // 输出到控制台
        Writer writer = new OutputStreamWriter(System.out);
        
        fos.close();
        out.close();
        writer.close();
        
     // 清空缓存
     FreeMarkerTemplateUtils.clearCache();
	}
	
	/**
	 * 将带有下划线的字符串变为驼峰格式的字符串
	 * @Title: replaceUnderLineAndUpperCase   
	 * @Description: TODO(这里用一句话描述这个方法的作用)   
	 * @param: @param str
	 * @param: @return      
	 * @return: String      
	 * @throws
	 * @author: zhangxz     
	 * @date:   2018年8月17日 下午11:15:08   
	 * @version V1.0
	 */
	public static String replaceUnderLineAndUpperCase(String str){
        StringBuffer sb = new StringBuffer();
        sb.append(str);
        // 将字符串中下划线链接处的字母变为大写字母
        int count = sb.indexOf("_");
        while(count!=0){
            int num = sb.indexOf("_",count);
            count = num + 1;
            if(num != -1){
                char ss = sb.charAt(count);
                char ia = (char) (ss - 32);// 变为大写字母
                sb.replace(count , count + 1,ia + "");
            }
        }
        String result = sb.toString().replaceAll("_","");
        return StringUtils.capitalize(result);
    }
	
	public static String firstCodeToUpperCase(String str) {
        char[] chars = str.toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] = (char)(chars[0] - 32);
        }
        return new String(chars);
	}
}
